/*
 Copyright (c) 2013 MeherTJ G. All rights reserved.
 License: LGPL for personnal study or free software.
 */

#pragma once

#include "zen_macro.h"

/// Main point.
/// implement the function.
/// create a sub AppDelegate. and return the object.
/// fill the config(not null) to initialize App.

// extern std::shared_ptr<Zen::AppDelegate> ZenAppMain(Zen::AppConfig* config);

#if !ZEN_IS_GUI
#error "app should Run in visual system"
#endif

// clean
#if ZEN_METAL
#undef ZEN_METAL
#define ZEN_METAL 1
#undef ZEN_GL
#define ZEN_GL 0

#elif ZEN_GL
#undef ZEN_GL
#define ZEN_GL 1
#undef ZEN_METAL
#define ZEN_METAL 0
#endif

#if ZEN_OS_IOS
// ios : metal/gles
#if !ZEN_METAL && !ZEN_GL
#error "no graphics selected, please define ZEN_METAL=1 or ZEN_GL=1 in preprocessor macros"
#endif

#elif defined(ZEN_OS_OSX)
// mac : metal
#define ZEN_METAL 1
#else
// android windows : gles
#define ZEN_GL 1
#endif

#include "zen_point.h"

namespace Zen
{
    struct AppKey
    {
        int type{};
        int value{};
    };

    struct AppTouch
    {
        int no{};
        float x{}, y{};
        float force{}; //(0,1) 3D touch.
    };

    enum class MouseButton : int
    {
        None = 0,
        Left = 1,
        Right = 2,
        Middle = 4,
    };
    struct AppMouse
    {
        MouseButton button{}; // left:1,right:2,middle:4,move:0
        float x{}, y{};
    };

    class AppDelegate
    {
    public:
        virtual ~AppDelegate() = default;

        /// life circle. [
        virtual void OnLaunch(Zen::Point2 view_size) {}

        virtual void OnResize(Zen::Point2 view_size) {}

        virtual void OnPause() {}

        virtual void OnResume() {}

        virtual void OnUpdate() {}

        virtual void OnDraw() {}

        virtual void OnExit() {}
        /// life circle. ]

        /// touch event... [
        virtual void OnTouchDown(AppTouch const& touch) {}

        virtual void OnTouchMove(AppTouch const& touch) {}

        virtual void OnTouchUp(AppTouch const& touch) {}

        virtual void OnTouchCancel(AppTouch const& touch) {}
        /// touch event... ]

        /// mouse event [
        virtual void OnMouseMove(AppMouse mouse) {}

        virtual void OnMouseKeyDown(AppMouse mouse) {}

        virtual void OnMouseKeyUp(AppMouse mouse) {}
        /// mouse event ]

        /// keyboard event. [
        virtual void OnKeyDown(AppKey key) {}

        virtual void OnKeyUp(AppKey key) {}
        /// keyboard event. ]

        /// customized event.
        virtual void OnEvent(std::string const& event, std::string const& data, long extra) {}
    };
} // namespace Zen

namespace Zen
{
    struct AppConfig
    {
        std::string Title{};
        int WindowWidth{}, WindowHeight{}; // only for windows.
        uint32_t Style{}; // only for windows.
        float FramesPerSecond{ 60 };
        bool IsMultiTouch{ false };
        bool IsRotatable{ true };
        bool IsStatusVisible{};
        bool IsBGUpdatable{};
    };

    class App
    {
    protected:
        App() = default;
        virtual ~App() = default;

    public:
        static std::shared_ptr<App> Only();

        virtual auto GetRuntimeDelegate() -> std::shared_ptr<AppDelegate> = 0;

        virtual bool IsMultiTouchEnabled() = 0;

        virtual void SetMultiTouchEnabled(bool) = 0;

        virtual bool IsRotatable() = 0;

        virtual void SetRotatable(bool) = 0;

        virtual float GetFramesPerSecond() = 0;

        virtual void SetFramesPerSecond(float) = 0;

        virtual bool IsStatusVisible() = 0;

        virtual void SetStatusVisible(bool) = 0;

        virtual void SetLowFrameRate(int) = 0;

        virtual int GetLowFrameRate() = 0;

        virtual bool IsBGUpdatable() = 0;

        virtual void SetBGUpdatable(bool) = 0;

        virtual void Terminate() = 0;
    };
} // namespace Zen

extern std::shared_ptr<Zen::AppDelegate> ZenAppMain(Zen::AppConfig* config);
